package prsnl.daan.ledbak;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

import javax.swing.JFrame;
import javax.swing.JPanel;

import prsnl.daan.ledbak.engine.Screen;
import prsnl.daan.ledbak.formations.Formation;
import prsnl.daan.ledbak.formations.Hexagon;


public class LedBakComponent extends Canvas implements Runnable{
	
	private static final long	serialVersionUID	= -4994384470113997739L;
	
	public static final int		WIDTH				= 160;
	public static final int		HEIGHT				= 120;
	public static final double	FACTOR				= 4;
	public static final double	FPS					= 60.0;
	
	private double				scale;
	
	private boolean				running				= false;
	private Thread				thread;
	
	private Formation			formation;
	private Screen				screen;
	private BufferedImage		img;
	private int[ ]				pixels;
	
	public LedBakComponent( ) {
		this( WIDTH, HEIGHT, FACTOR );
	}
	
	public LedBakComponent( int width, int height, double scale ) {
		this.scale = scale;
		Dimension dim = new Dimension( (int) ( width * scale ), (int) ( height * scale ) );
		
		setSize( dim );
		setPreferredSize( dim );
		setMaximumSize( dim );
		setMinimumSize( dim );
		
		screen = new Screen( width, height );
		img = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
		pixels = ( (DataBufferInt) img.getRaster( ).getDataBuffer( ) ).getData( );
		
		formation = new Hexagon( );
	}
	
	public synchronized void start( ) {
		if(running) return;
		running = true;
		thread = new Thread( this );
		thread.start( );
	}
	
	public synchronized void stop( ) {
		if(!running) return;
		running = false;
		try{
			thread.join( );
		} catch(InterruptedException ie){
			ie.printStackTrace( );
		}
	}
	
	@Override
	public void run( ) {
		int frames = 0;
		double unprocessSeconds = 0;
		long lastTime = System.nanoTime( );
		double secondsPerTick = 1 / FPS;
		int tickCount = 0;
		
		while(running){
			long now = System.nanoTime( );
			long passedTime = now - lastTime;
			lastTime = now;
			if(passedTime < 0) passedTime = 0;
			if(passedTime > 1000000000) passedTime = 1000000000;
			
			unprocessSeconds += passedTime / 1000000000.0;
			
			boolean ticked = false;
			while(unprocessSeconds > secondsPerTick){
				tick( );
				unprocessSeconds -= secondsPerTick;
				ticked = true;
				
				tickCount++;
				if(tickCount % ( (int) FPS ) == 0){
					System.out.println( frames + " fps" );
					lastTime += 1000;
					frames = 0;
				}
			}
			
			if(ticked){
				render( );
				frames++;
			} else{
				try{
					Thread.sleep( 1 );
				} catch(InterruptedException e){
					e.printStackTrace( );
				}
			}
		}
	}
	
	private void tick( ) {
		formation.tick( );
	}
	
	private void render( ) {
		BufferStrategy bs = getBufferStrategy( );
		if(bs == null){
			createBufferStrategy( 3 );
			return;
		}
		
		screen.render( formation );
		
		System.arraycopy( screen.getPixels( ), 0, pixels, 0, screen.getPixels( ).length );
		
		Graphics g = bs.getDrawGraphics( );
		g.fillRect( 0, 0, getWidth( ), getHeight( ) );
		g.drawImage( img, 0, 0, getWidth( ), getHeight( ), null );
		g.dispose( );
		bs.show( );
	}
	
	public static void main( String[ ] args ) {
		LedBakComponent lbC = new LedBakComponent( );
		
		JFrame frame = new JFrame( "LED Bak calculator" );
		
		JPanel panel = new JPanel( new BorderLayout( ) );
		panel.add( lbC, BorderLayout.CENTER );
		
		frame.setContentPane( panel );
		frame.pack( );
		frame.setLocationRelativeTo( null );
		frame.setResizable( false );
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		frame.setVisible( true );
		
		lbC.start( );
	}
}
